package simple_sql

import (
	"fmt"
	"gitee.com/jn-qq/go-tools/slices"
	"reflect"
	"strings"
)

type Operator interface {
	toSql() (string, []any, error)
}

type operatorSymbol string

const (
	greaterThan      operatorSymbol = ">"
	lessThan         operatorSymbol = "<"
	equal            operatorSymbol = "="
	notEqual         operatorSymbol = "!="
	greaterThanEqual operatorSymbol = ">="
	lessThanEqual    operatorSymbol = "<="
	in               operatorSymbol = "IN"
	notIn            operatorSymbol = "NOT IN"
	like             operatorSymbol = "LIKE"
	notLike          operatorSymbol = "NOT LIKE"
	between          operatorSymbol = "BETWEEN"
	notBetween       operatorSymbol = "NOT BETWEEN"
	isNull           operatorSymbol = "IS NULL"
	isNotNull        operatorSymbol = "IS NOT NULL"
)

// Eq 等于
type Eq struct {
	Filed string
	Value any
}

// Neq 不等于
type Neq struct {
	Filed string
	Value any
}

// Gt 大于
type Gt struct {
	Filed string
	Value any
}

// Lt 小于
type Lt struct {
	Filed string
	Value any
}

// Gte 大于等于
type Gte struct {
	Filed string
	Value any
}

// Lte 小于等于
type Lte struct {
	Filed string
	Value any
}

type In struct {
	Filed string
	Value []any
}
type NotIn struct {
	Filed string
	Value []any
}
type Like struct {
	Filed string
	Value any
}
type NotLike struct {
	Filed string
	Value any
}
type Between struct {
	Filed string
	Value [2]any
}
type NotBetween struct {
	Filed string
	Value [2]any
}
type IsNull struct {
	Filed string
}
type IsNotNull struct {
	Filed string
}

func (i In) toSql() (string, []any, error)         { return toSql(i.Filed, i.Value, in) }
func (i NotIn) toSql() (string, []any, error)      { return toSql(i.Filed, i.Value, notIn) }
func (l Lte) toSql() (string, []any, error)        { return toSql(l.Filed, l.Value, lessThanEqual) }
func (g Gte) toSql() (string, []any, error)        { return toSql(g.Filed, g.Value, greaterThanEqual) }
func (l Lt) toSql() (string, []any, error)         { return toSql(l.Filed, l.Value, lessThan) }
func (g Gt) toSql() (string, []any, error)         { return toSql(g.Filed, g.Value, greaterThan) }
func (n Neq) toSql() (string, []any, error)        { return toSql(n.Filed, n.Value, notEqual) }
func (e Eq) toSql() (string, []any, error)         { return toSql(e.Filed, e.Value, equal) }
func (l Like) toSql() (string, []any, error)       { return toSql(l.Filed, l.Value, like) }
func (n NotLike) toSql() (string, []any, error)    { return toSql(n.Filed, n.Value, notLike) }
func (b Between) toSql() (string, []any, error)    { return toSql(b.Filed, b.Value, between) }
func (n NotBetween) toSql() (string, []any, error) { return toSql(n.Filed, n.Value, notBetween) }
func (i IsNull) toSql() (string, []any, error)     { return toSql(i.Filed, nil, isNull) }
func (n IsNotNull) toSql() (string, []any, error)  { return toSql(n.Filed, nil, isNotNull) }

func toSql(field string, value any, operator operatorSymbol) (string, []any, error) {
	if operator != isNull && operator != isNotNull && value == nil {
		return "", nil, fmt.Errorf("operator must have a value")
	}
	switch operator {
	case greaterThan, lessThan, greaterThanEqual, lessThanEqual, equal, notEqual, like, notLike:
		if !slices.Contains(baseFieldType, reflect.ValueOf(value).Kind()) {
			return "", nil, fmt.Errorf("不支持的字段类型")
		}
		return fmt.Sprintf(" %s %s ?", field, operator), []any{value}, nil
	case in, notIn:
		v := value.([]any)
		return fmt.Sprintf(" %s %s (%s)", field, operator, strings.Repeat("?,", len(v)-1)+"?"), v, nil
	case between, notBetween:
		v := value.([2]any)
		return fmt.Sprintf(" %s %s ? AND ?", field, operator), []any{v[0], v[1]}, nil
	case isNull, isNotNull:
		return fmt.Sprintf(" %s %s", field, operator), nil, nil
	default:
		return "", nil, fmt.Errorf("operator must be one of the following: %v", operator)
	}
}

// 支持过滤查询的基础数据类型
var baseFieldType = []reflect.Kind{
	reflect.String, reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int8,
	reflect.Float64, reflect.Float32, reflect.Bool,
}
